using System;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security.Permissions;
using Microsoft.Practices.SharePoint.Common.Configuration;
using Microsoft.Practices.SharePoint.Common.Logging;
using Microsoft.Practices.SharePoint.Common.ServiceLocation;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Security;

namespace ITSP.SharePoint.CacheRefresh.Features.RegisterDiagnosticLogging
{
    /// <summary>
    /// This class handles events raised during feature activation, deactivation, installation, uninstallation, and upgrade.
    /// </summary>
    /// <remarks>
    /// The GUID attached to this class may be used during packaging and should not be modified.
    /// </remarks>

    [Guid("4a318b28-0f1f-48e8-bf22-1cfc7aae248c")]
    public class RegisterDiagnosticLoggingEventReceiver : SPFeatureReceiver
    {

        /// <summary>
        /// Register the Diagnostic Logging Area and Categories
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            try
            {
                RegisterLoggingCategories();

            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// Unregister the Diagnostic Logging Area and Categories
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            try
            {
                UnregisterLoggingCategories();
            }
            catch (Exception)
            {

                throw;
            }
        }

        /// <summary>
        /// Called when the Feature is Installed.
        /// </summary>
        /// <param name="properties"></param>
        public override void FeatureInstalled(SPFeatureReceiverProperties properties)
        {
            RegisterLoggingCategories();
        }

        /// <summary>
        /// General Logging Area for SharePoint Logging used by Diagnostics Service
        /// </summary>
        private readonly string sharePointLoggingArea = "iThink SharePoint";

        /// <summary>
        /// General Logging Category for SharePoint Logging used by Diagnostics Service
        /// </summary>
        private readonly string[] sharePointLoggingCategories = {"General"};

        /// <summary>
        /// This function registers the logging diagnostic categories and areas.
        /// The areas that are being registered are the out of the box sharePoint feature receiver categories.
        /// The function also registers the Logging Library, this needs to occur first otherwise the Logging will fail.
        /// </summary>
        private bool RegisterLoggingCategories()
        {
            bool bSuccess = false;

            try
            {


                //register the diagnostics service.
                DiagnosticsService.Register();
                ILogger logger = SharePointServiceLocator.GetCurrent().GetInstance<ILogger>();
                logger.TraceToDeveloper("Registering the SharePoint Patterns and Practice Logging Library", 10000);

                //register the diagnostic categories and areas.
                IConfigManager configManager = SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
                DiagnosticsAreaCollection diagnosticsAreaCollection = new DiagnosticsAreaCollection(configManager);
                DiagnosticsArea configureLoggingArea =
                    diagnosticsAreaCollection.FirstOrDefault(area => area.Name == sharePointLoggingArea);

                if (configureLoggingArea == null)
                {
                    configureLoggingArea = new DiagnosticsArea(sharePointLoggingArea);
                    logger.TraceToDeveloper(String.Format("Creating Diagnostic Area {0}", configureLoggingArea.Name),
                                            TraceSeverity.Monitorable);
                }

                //check that all the categories are installed.
                foreach (string sharePointLoggingCategory in sharePointLoggingCategories)
                {
                    logger.TraceToDeveloper(
                        String.Format("Checking for Diagnostic Category {0} in {1}", sharePointLoggingCategory,
                                      sharePointLoggingArea), TraceSeverity.Monitorable);

                    SPDiagnosticsCategory checkCategory = GetDiagnosticCategory(sharePointLoggingCategory);
                    if (checkCategory == null)
                    {
                        DiagnosticsCategory localcategory = new DiagnosticsCategory(sharePointLoggingCategory);
                        configureLoggingArea.DiagnosticsCategories.Add(localcategory);
                        logger.TraceToDeveloper(
                            String.Format("Creating Diagnostic Category {0} in {1}", sharePointLoggingCategory,
                                          sharePointLoggingArea), TraceSeverity.Monitorable);
                    }
                }

                logger.TraceToDeveloper(
                    String.Format("Saving Logging Diagnostic Areas {0}", configureLoggingArea.Name),
                    TraceSeverity.Monitorable);
                diagnosticsAreaCollection.Add(configureLoggingArea);
                diagnosticsAreaCollection.SaveConfiguration();

                logger.TraceToDeveloper(
                    String.Format("Registered the SharePoint Patterns and Practice Logging Configuration", 10000));
                logger.LogToOperations(String.Format("Registered the SharePoint Patterns and Practices Logging"),
                                       EventSeverity.Information);

                bSuccess = true;
            }
            catch (Exception)
            {

                throw;
            }

            return bSuccess;
        }

        /// <summary>
        /// This function unregisters the logging diagnostic categories and areas.
        /// </summary>
        private bool UnregisterLoggingCategories()
        {
            bool bSuccess = false;

            try
            {
                //register the diagnostics service.
                DiagnosticsService.Register();
                ILogger logger = SharePointServiceLocator.GetCurrent().GetInstance<ILogger>();
                logger.TraceToDeveloper("Registering the SharePoint Patterns and Practice Logging Library", 10000);

                //unregister the diagnostic categories and areas.
                IConfigManager configManager = SharePointServiceLocator.GetCurrent().GetInstance<IConfigManager>();
                DiagnosticsAreaCollection diagnosticsAreaCollection = new DiagnosticsAreaCollection(configManager);
                DiagnosticsArea configureLoggingArea =
                    diagnosticsAreaCollection.FirstOrDefault(area => area.Name == sharePointLoggingArea);

                if (configureLoggingArea != null)
                {
                    //remove the categories from the area
                    foreach (string sharePointLoggingCategory in sharePointLoggingCategories)
                    {
                        logger.TraceToDeveloper(
                            String.Format("Checking for Diagnostic Category {0} in {1}", sharePointLoggingCategory,
                                          sharePointLoggingArea), TraceSeverity.Monitorable);

                        DiagnosticsCategory checkCategory =
                            configureLoggingArea.DiagnosticsCategories.FirstOrDefault(
                                cat => cat.Name == sharePointLoggingCategory);
                        if (checkCategory != null)
                        {
                            logger.TraceToDeveloper(
                                String.Format("Removing Diagnostic Category {0} in {1}", sharePointLoggingCategory,
                                              sharePointLoggingArea), TraceSeverity.Monitorable);
                            configureLoggingArea.DiagnosticsCategories.Remove(checkCategory);
                        }
                    }

                    logger.TraceToDeveloper(String.Format("Removing Diagnostic Area {0}", configureLoggingArea.Name),
                                            TraceSeverity.Monitorable);

                    diagnosticsAreaCollection.Remove(configureLoggingArea);
                    diagnosticsAreaCollection.SaveConfiguration();

                    logger.TraceToDeveloper(String.Format("Saving Diagnostic Areas {0}", configureLoggingArea.Name),
                                            TraceSeverity.Monitorable);
                }

                logger.TraceToDeveloper(String.Format("Unregistered the SharePoint Diagnostics Logging Configuration",
                                                      10000));

                bSuccess = true;
            }
            catch (Exception)
            {

                throw;
            }

            return bSuccess;
        }


        /// <summary>
        /// Gets the SharePoint Diagnostic Service Area
        /// </summary>
        /// <param name="areaName"></param>
        /// <returns></returns>
        internal SPDiagnosticsArea GetDiagnosticsArea(string areaName)
        {
            SPDiagnosticsArea diagnosticsArea = null;
            try
            {

                DiagnosticsService diagnosticService = DiagnosticsService.Local;
                diagnosticsArea = diagnosticService.Areas.SingleOrDefault(a => a.Name == areaName);
            }
            catch (Exception)
            {
                throw;
            }
            return diagnosticsArea;
        }

        /// <summary>
        /// Get the Diagnostic Category to use to Log to the SharePoint ULS Log with.
        /// </summary>
        /// <returns>The diagnostics category that are to be used to log in the Feature Receiver.</returns>
        internal SPDiagnosticsCategory GetDiagnosticCategory(string categoryName)
        {
            SPDiagnosticsCategory diagnosticsCategory = null;
            try
            {
                SPDiagnosticsArea diagnosticsArea = GetDiagnosticsArea(sharePointLoggingArea);
                if (diagnosticsArea != null)
                {
                    diagnosticsCategory = diagnosticsArea.Categories.SingleOrDefault(c => c.Name == categoryName);
                }

            }
            catch (Exception)
            {
                throw;
            }
            return diagnosticsCategory;
        }

        /// <summary>
        /// Get the Category Path which includes the Category Area appended to the start of the string.
        /// </summary>
        /// <returns></returns>
        internal string GetDiagnosticCategoryPath(string categoryName)
        {
            string categoryPath = String.Empty;
            try
            {
                SPDiagnosticsCategory category = GetDiagnosticCategory(categoryName);
                categoryPath = String.Format("{0}/{1}", category.Area.Name, category.Name);
            }
            catch (Exception)
            {

                throw;
            }

            return categoryPath;

        }
    }
}